(function ($, window, document, undefined) {

$(document).ready(function() {
	
	$klass = $.klass;
	$proto = $klass.prototype;
	$trait = $.trait;
	Trait = $klass.Trait;
	
	module("Wiki Traits");
	
	test("", function() {
		
	// Simple traits
		Draggable = $.trait({  // Create a new trait.
		  drag: function( ) {
			return "I can be dragged.";
		  }
		});
		
		Resizeable = $.trait({
		  resize: function( ) {
			return "I can be resized.";
		  }
		});
		
		Square = $.klass({
		  init: function( ) { },
		  _traits: [ Draggable, Resizeable ]  // Lists the traits to be added to the class
		});
		
		s1 = new Square();
		strictEqual(s1.drag(), "I can be dragged.", 's1.drag()');  // => "I can be dragged."
		strictEqual(s1.resize(), "I can be resized.", 's1.resize()');  // => "I can be resized."
		strictEqual(s1._traits, undefined, 's1._traits');  // => undefined
		
		// You cannot use instanceof for traits, but you can use the following:
		strictEqual(!! s1._hasTrait( Draggable ), true, '!! s1._hasTrait( Draggable )');  // => true  "!!" coerces the value to a boolean
		strictEqual(s1._hasTrait( Draggable ), Square, 's1._hasTrait( Draggable )');  // => Square  ie: Square is the closest class that implements that trait
		
		methods = {
		  func: function() { }
		};
		UnusedTrait = $.trait( methods );
		notrait = new ( $.klass( methods ) )();
		strictEqual(!! notrait._hasTrait( UnusedTrait ), false, '!! notrait._hasTrait( UnusedTrait )');  // => false
		strictEqual(notrait._hasTrait( UnusedTrait ), undefined, 'notrait._hasTrait( UnusedTrait )');  // => undefined

		
	// Creating traits and name conflicts
		SizeAnimation = $.trait({
		  animate: function( finalSize ) {
			return "Animating size to " + finalSize + ".";
		  }
		});
		
		ColorAnimation = $.trait({
		  animate: function( finalColor ) {
			return "Animating color to " + finalColor + ".";
		  }
		});
		
		Square = $.klass({
		  animate: function( finalSize, finalColor) {  // Redefining the "animate" function resolve the conflict.
			// Call each trait methods:
			return this._trait( arguments, SizeAnimation, finalSize ) + " "
			  + this._trait( arguments, ColorAnimation, finalColor );
		  },
		  animateColor: function( finalColor) {
			// Call the method "animate" of the trait ColorAnimation:
			return this._trait( "animate", arguments, ColorAnimation, finalColor );
		  },
		  _traits: [ SizeAnimation, ColorAnimation ]  // Name conflict: both have an "animate" function
		});
		
		square = new Square();
		strictEqual(square.animate( "large", "red" ), "Animating size to large. Animating color to red.", 'square.animate( "large", "red" )');  // => null;  // => "Animating size to large. Animating color to red."
		strictEqual(square.animateColor( "yellow" ), "Animating color to yellow.", 'square.animateColor( "yellow" )');  // => "Animating color to yellow."
		
		// The following throws an exception because the name conflict is not resolved:
		raises(function() {
			Conflicting = $.klass({
			  _traits: [ SizeAnimation, ColorAnimation ]
			});
		}, /Method name conflict: animate/, 'Conflicting = $.klass({ ...');

		
	// Temporary
		// If you use in a trait a function that is already used as a method in a klass:
		SimpleParent = $.klass({
		  ask: function( ) {
			return "Simple";
		  }
		});
		
		TraitParent = $.klass({
		  ask: function( ) {
			return "Trait";
		  }
		});
		
		// The guilty function (will be added to SimpleChild and TraitChild):
		ask = function( who ) {
		  return who ? who.ask( ) : this._super( arguments );
		};
		
		SimpleChild = $.klass( SimpleParent, {
		  ask: ask
		});
		
		AskNameTrait = $.trait( { ask: ask } );
		TraitChild = $.klass( TraitParent, {
		  _traits: [ AskNameTrait ]
		});
		
		sc = new SimpleChild( );
		tc = new TraitChild( );
		
		strictEqual(sc.ask( tc ), "Trait", 'sc.ask( tc )');  // => "Trait"
		strictEqual(tc.ask( sc ), "Trait", 'tc.ask( sc )');  // => "Trait", not "Simple" !
	});
});

})(jQuery, window, window.document);